<!doctype html>
<html>
  <head>
    <title>交互式绘图板 - Vue事件处理实践</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        background: #f0f2f5;
        overflow: hidden;
      }

      .drawing-app {
        display: flex;
        height: 100vh;
      }

      .toolbar {
        width: 250px;
        background: white;
        border-right: 1px solid #e1e5e9;
        padding: 20px;
        overflow-y: auto;
      }

      .toolbar h3 {
        margin-bottom: 15px;
        color: #333;
        border-bottom: 2px solid #667eea;
        padding-bottom: 5px;
      }

      .tool-group {
        margin-bottom: 20px;
      }

      .tool-group label {
        display: block;
        margin-bottom: 5px;
        font-weight: 600;
        color: #555;
      }

      .tool-buttons {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 10px;
        margin-bottom: 15px;
      }

      .tool-btn {
        padding: 10px;
        border: 2px solid #e1e5e9;
        background: white;
        border-radius: 8px;
        cursor: pointer;
        transition: all 0.3s ease;
        text-align: center;
        font-size: 14px;
      }

      .tool-btn:hover {
        border-color: #667eea;
        background: #f8f9ff;
      }

      .tool-btn.active {
        border-color: #667eea;
        background: #667eea;
        color: white;
      }

      .color-palette {
        display: grid;
        grid-template-columns: repeat(6, 1fr);
        gap: 5px;
        margin-bottom: 15px;
      }

      .color-btn {
        width: 30px;
        height: 30px;
        border: 2px solid #ddd;
        border-radius: 50%;
        cursor: pointer;
        transition: transform 0.2s ease;
      }

      .color-btn:hover {
        transform: scale(1.1);
      }

      .color-btn.active {
        border-color: #333;
        transform: scale(1.2);
      }

      .slider-group {
        margin-bottom: 15px;
      }

      .slider {
        width: 100%;
        margin: 10px 0;
      }

      .action-buttons {
        display: flex;
        flex-direction: column;
        gap: 10px;
      }

      .action-btn {
        padding: 12px;
        border: none;
        border-radius: 8px;
        cursor: pointer;
        font-weight: 600;
        transition: all 0.3s ease;
      }

      .action-btn.primary {
        background: #667eea;
        color: white;
      }

      .action-btn.secondary {
        background: #6c757d;
        color: white;
      }

      .action-btn.danger {
        background: #e74c3c;
        color: white;
      }

      .action-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      }

      .action-btn:disabled {
        opacity: 0.5;
        cursor: not-allowed;
        transform: none;
      }

      .canvas-container {
        flex: 1;
        position: relative;
        background: white;
        margin: 20px;
        border-radius: 10px;
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
        overflow: hidden;
      }

      .canvas {
        display: block;
        cursor: crosshair;
      }

      .canvas.eraser {
        cursor:
          url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><rect width="20" height="20" fill="%23ff6b6b" rx="2"/></svg>')
            10 10,
          auto;
      }

      .status-bar {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(0, 0, 0, 0.8);
        color: white;
        padding: 10px 20px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        font-size: 14px;
      }

      .shortcuts-panel {
        position: absolute;
        top: 20px;
        right: 20px;
        background: rgba(255, 255, 255, 0.95);
        padding: 15px;
        border-radius: 8px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        font-size: 12px;
        max-width: 200px;
      }

      .shortcuts-panel h4 {
        margin-bottom: 10px;
        color: #333;
      }

      .shortcut-item {
        display: flex;
        justify-content: space-between;
        margin: 5px 0;
      }

      .shortcut-key {
        background: #e1e5e9;
        padding: 2px 6px;
        border-radius: 3px;
        font-family: monospace;
      }

      /* 学生模板特殊样式 */
      .template-header {
        background: linear-gradient(135deg, #9C27B0 0%, #7B1FA2 100%);
        color: white;
        padding: 10px 20px;
        text-align: center;
        font-weight: bold;
        border-bottom: 3px solid #6A1B9A;
      }

      /* 键盘提示样式 */
      .keyboard-hint {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: rgba(0, 0, 0, 0.8);
        color: white;
        padding: 20px;
        border-radius: 10px;
        font-size: 18px;
        z-index: 1000;
        opacity: 0;
        transition: opacity 0.3s ease;
      }

      .keyboard-hint.show {
        opacity: 1;
      }

      /* 历史记录指示器 */
      .history-indicator {
        position: absolute;
        top: 20px;
        left: 20px;
        background: rgba(255, 255, 255, 0.95);
        padding: 10px;
        border-radius: 8px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        font-size: 12px;
        min-width: 150px;
      }

      .history-indicator h4 {
        margin-bottom: 8px;
        color: #333;
      }

      .history-bar {
        height: 4px;
        background: #e1e5e9;
        border-radius: 2px;
        margin: 5px 0;
        position: relative;
      }

      .history-progress {
        height: 100%;
        background: #667eea;
        border-radius: 2px;
        transition: width 0.3s ease;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- 任务6完成标识 -->
      <div class="template-header">✅ 任务6完成 - 撤销重做功能 | Vue状态管理实践</div>

      <!-- 键盘提示 -->
      <div class="keyboard-hint" :class="{ show: showKeyboardHint }">
        {{ keyboardHintText }}
      </div>

      <div class="drawing-app">
        <!-- 工具栏 -->
        <div class="toolbar">
          <h3>🎨 绘图工具</h3>

          <!-- 绘制工具 -->
          <div class="tool-group">
            <label>绘制工具</label>
            <div class="tool-buttons">
              <!-- ✅ 任务1完成: 添加工具选择的Vue事件处理 -->
              <button 
                v-for="tool in tools" 
                :key="tool.name"
                class="tool-btn" 
                :class="{ active: currentTool === tool.name }"
                @click="setTool(tool.name)"
              >
                {{ tool.icon }} {{ tool.label }}
              </button>
            </div>
          </div>

          <!-- 颜色选择 -->
          <div class="tool-group">
            <label>颜色选择</label>
            <div class="color-palette">
              <!-- ✅ 任务2完成: 添加颜色选择的Vue事件处理 -->
              <button 
                v-for="color in colors" 
                :key="color"
                class="color-btn" 
                :class="{ active: currentColor === color }"
                :style="{ backgroundColor: color }"
                @click="setColor(color)"
              ></button>
            </div>
            <!-- ✅ 任务2完成: 添加颜色选择器的Vue双向绑定 -->
            <input
              type="color"
              v-model="currentColor"
              style="width: 100%; height: 40px; border: none; border-radius: 5px"
            />
          </div>

          <!-- 画笔设置 -->
          <div class="tool-group">
            <div class="slider-group">
              <!-- ✅ 任务3完成: 添加画笔大小的Vue双向绑定和显示 -->
              <label>画笔大小: {{ brushSize }}px</label>
              <input 
                type="range" 
                v-model.number="brushSize" 
                min="1" 
                max="50" 
                class="slider" 
              />
            </div>

            <div class="slider-group">
              <!-- ✅ 任务3完成: 添加透明度的Vue双向绑定和显示 -->
              <label>透明度: {{ Math.round(opacity * 100) }}%</label>
              <input 
                type="range" 
                v-model.number="opacity" 
                min="0.1" 
                max="1" 
                step="0.1" 
                class="slider" 
              />
            </div>
          </div>

          <!-- 操作按钮 -->
          <div class="tool-group">
            <label>操作</label>
            <div class="action-buttons">
              <!-- ✅ 任务6完成: 添加按钮的Vue事件处理和状态控制 -->
              <button 
                class="action-btn secondary" 
                :disabled="!canUndo"
                @click="undo"
              >
                ↶ 撤销 (Ctrl+Z)
              </button>
              <button 
                class="action-btn secondary" 
                :disabled="!canRedo"
                @click="redo"
              >
                ↷ 重做 (Ctrl+Y)
              </button>
              <button class="action-btn primary" @click="saveImage">💾 保存 (Ctrl+S)</button>
              <button class="action-btn danger" @click="clearCanvas">🗑️ 清空 (Ctrl+Delete)</button>
            </div>
          </div>

          <!-- 统计信息 -->
          <div class="tool-group">
            <label>统计信息</label>
            <div style="font-size: 14px; color: #666">
              <!-- ✅ 任务4完成: 添加动态统计信息的Vue数据绑定 -->
              <div>笔画数: {{ strokeCount }}</div>
              <!-- ✅ 任务6完成: 添加历史记录统计 -->
              <div>历史记录: {{ historyIndex + 1 }}/{{ history.length }}</div>
              <div>画布大小: {{ canvasWidth }}×{{ canvasHeight }}</div>
              <!-- ✅ 任务5完成: 添加键盘状态显示 -->
              <div>最后按键: {{ lastKeyPressed || '无' }}</div>
            </div>
          </div>
        </div>

        <!-- 画布区域 -->
        <div class="canvas-container">
          <!-- 历史记录指示器 -->
          <div class="history-indicator">
            <h4>📚 历史记录</h4>
            <div>当前: {{ historyIndex + 1 }}/{{ history.length }}</div>
            <div class="history-bar">
              <div 
                class="history-progress" 
                :style="{ width: history.length > 0 ? ((historyIndex + 1) / history.length * 100) + '%' : '0%' }"
              ></div>
            </div>
            <div style="margin-top: 5px; font-size: 11px; color: #666;">
              撤销: {{ canUndo ? '可用' : '不可用' }} | 重做: {{ canRedo ? '可用' : '不可用' }}
            </div>
          </div>

          <!-- ✅ 任务5完成: 添加画布的键盘事件处理 -->
          <canvas 
            ref="canvas" 
            class="canvas" 
            :class="{ eraser: currentTool === 'eraser' }"
            width="800" 
            height="600" 
            tabindex="0"
            @mousedown.prevent="startDrawing"
            @mousemove.prevent="draw"
            @mouseup.prevent="stopDrawing"
            @mouseleave.prevent="stopDrawing"
            @keydown.prevent="handleKeyboard"
            @focus="() => console.log('画布获得焦点')"
          ></canvas>

          <!-- 状态栏 -->
          <div class="status-bar">
            <div>
              <!-- ✅ 任务1&2&3完成: 添加动态状态信息的Vue数据绑定 -->
              工具: {{ getCurrentToolLabel() }} | 颜色: {{ currentColor }} | 大小: {{ brushSize }}px | 透明度: {{ Math.round(opacity * 100) }}%
            </div>
            <div>
              <!-- ✅ 任务4&5&6完成: 添加鼠标位置、绘制状态、键盘状态和历史状态的Vue数据绑定 -->
              坐标: ({{ mouseX }}, {{ mouseY }}) | {{ isDrawing ? '绘制中' : '就绪' }} | 焦点: {{ hasFocus ? '是' : '否' }} | 历史: {{ historyIndex + 1 }}/{{ history.length }}
            </div>
          </div>

          <!-- 快捷键面板 -->
          <div class="shortcuts-panel">
            <h4>⌨️ 快捷键</h4>
            <div class="shortcut-item">
              <span>画笔</span>
              <span class="shortcut-key">B</span>
            </div>
            <div class="shortcut-item">
              <span>橡皮</span>
              <span class="shortcut-key">E</span>
            </div>
            <div class="shortcut-item">
              <span>直线</span>
              <span class="shortcut-key">L</span>
            </div>
            <div class="shortcut-item">
              <span>矩形</span>
              <span class="shortcut-key">R</span>
            </div>
            <div class="shortcut-item">
              <span>圆形</span>
              <span class="shortcut-key">C</span>
            </div>
            <div class="shortcut-item">
              <span>撤销</span>
              <span class="shortcut-key">Ctrl+Z</span>
            </div>
            <div class="shortcut-item">
              <span>重做</span>
              <span class="shortcut-key">Ctrl+Y</span>
            </div>
            <div class="shortcut-item">
              <span>保存</span>
              <span class="shortcut-key">Ctrl+S</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <script>
      const { createApp, ref, reactive, computed, onMounted, onUnmounted, nextTick } = Vue

      createApp({
        setup() {
          // ===== 响应式数据定义 =====
          const canvas = ref(null)
          let ctx = null

          // 绘制状态
          const isDrawing = ref(false)
          const currentTool = ref('brush')
          const currentColor = ref('#000000')
          const brushSize = ref(5)
          const opacity = ref(1)
          const mouseX = ref(0)
          const mouseY = ref(0)
          const strokeCount = ref(0)

          // ✅ 任务5完成: 键盘相关状态
          const lastKeyPressed = ref('')
          const hasFocus = ref(false)
          const showKeyboardHint = ref(false)
          const keyboardHintText = ref('')

          // 画布尺寸
          const canvasWidth = ref(800)
          const canvasHeight = ref(600)

          // ✅ 任务6完成: 历史记录管理
          const history = ref([])
          const historyIndex = ref(-1)
          const maxHistorySize = 50 // 限制历史记录数量

          // 绘制数据
          let startX = 0
          let startY = 0
          let lastX = 0
          let lastY = 0

          // ✅ 任务1完成: 工具定义
          const tools = [
            { name: 'brush', label: '画笔', icon: '🖌️', key: 'B' },
            { name: 'eraser', label: '橡皮', icon: '🧽', key: 'E' },
            { name: 'line', label: '直线', icon: '📏', key: 'L' },
            { name: 'rectangle', label: '矩形', icon: '⬜', key: 'R' },
            { name: 'circle', label: '圆形', icon: '⭕', key: 'C' },
            { name: 'text', label: '文字', icon: '📝', key: 'T' }
          ]

          // ✅ 任务2完成: 颜色调色板
          const colors = [
            '#000000',
            '#ffffff',
            '#ff0000',
            '#00ff00',
            '#0000ff',
            '#ffff00',
            '#ff00ff',
            '#00ffff',
            '#800000',
            '#008000',
            '#000080',
            '#808000',
            '#800080',
            '#008080',
            '#c0c0c0',
            '#808080',
            '#ff9999',
            '#99ff99'
          ]

          // ===== 计算属性 =====
          // ✅ 任务6完成: 撤销重做状态判断
          const canUndo = computed(() => {
            return historyIndex.value > 0
          })

          const canRedo = computed(() => {
            return historyIndex.value < history.value.length - 1
          })

          // ✅ 任务1完成: 获取当前工具标签
          const getCurrentToolLabel = () => {
            const tool = tools.find(t => t.name === currentTool.value)
            return tool ? tool.label : '画笔'
          }

          // ===== 方法定义 =====

          // ✅ 任务1完成: 设置工具
          const setTool = toolName => {
            currentTool.value = toolName
            const tool = tools.find(t => t.name === toolName)
            showKeyboardHint.value = true
            keyboardHintText.value = `切换到 ${tool ? tool.label : toolName}`
            setTimeout(() => {
              showKeyboardHint.value = false
            }, 1000)
            console.log('切换工具:', toolName)
          }

          // ✅ 任务2完成: 设置颜色
          const setColor = color => {
            currentColor.value = color
            console.log('切换颜色:', color)
          }

          // ✅ 任务6完成: 保存画布状态
          const saveState = () => {
            const imageData = ctx.getImageData(0, 0, canvasWidth.value, canvasHeight.value)
            
            // 删除当前索引之后的历史记录
            history.value = history.value.slice(0, historyIndex.value + 1)
            
            // 添加新状态
            history.value.push(imageData)
            historyIndex.value = history.value.length - 1
            
            // 限制历史记录数量
            if (history.value.length > maxHistorySize) {
              history.value.shift()
              historyIndex.value--
            }
            
            console.log('保存状态，当前历史记录数:', history.value.length)
          }

          // ✅ 任务4完成: 更新鼠标位置
          const updateMousePosition = event => {
            const rect = canvas.value.getBoundingClientRect()
            mouseX.value = Math.round(event.clientX - rect.left)
            mouseY.value = Math.round(event.clientY - rect.top)
          }

          // ✅ 任务4完成: 开始绘制
          const startDrawing = event => {
            updateMousePosition(event)
            isDrawing.value = true
            
            // 设置画布样式
            ctx.lineWidth = brushSize.value
            ctx.globalAlpha = opacity.value
            ctx.strokeStyle = currentColor.value
            ctx.lineCap = 'round'
            ctx.lineJoin = 'round'
            
            // 开始新路径
            ctx.beginPath()
            ctx.moveTo(mouseX.value, mouseY.value)
            
            console.log('开始绘制:', mouseX.value, mouseY.value)
          }

          // ✅ 任务4完成: 绘制过程
          const draw = event => {
            updateMousePosition(event)
            
            if (!isDrawing.value) return
            
            if (currentTool.value === 'brush') {
              // 画笔工具
              ctx.globalCompositeOperation = 'source-over'
              ctx.lineTo(mouseX.value, mouseY.value)
              ctx.stroke()
            } else if (currentTool.value === 'eraser') {
              // 橡皮擦工具
              ctx.globalCompositeOperation = 'destination-out'
              ctx.lineTo(mouseX.value, mouseY.value)
              ctx.stroke()
            }
          }

          // ✅ 任务4&6完成: 结束绘制并保存状态
          const stopDrawing = event => {
            if (isDrawing.value) {
              isDrawing.value = false
              strokeCount.value++
              
              // ✅ 任务6完成: 绘制结束后保存状态
              saveState()
              
              console.log('结束绘制，总笔画数:', strokeCount.value)
            }
          }

          // ✅ 任务5完成: 键盘事件处理
          const handleKeyboard = event => {
            const key = event.key.toLowerCase()
            lastKeyPressed.value = event.key
            
            // 防止默认行为
            event.preventDefault()
            
            // 工具快捷键
            switch (key) {
              case 'b':
                setTool('brush')
                break
              case 'e':
                setTool('eraser')
                break
              case 'l':
                setTool('line')
                break
              case 'r':
                setTool('rectangle')
                break
              case 'c':
                setTool('circle')
                break
              case 't':
                setTool('text')
                break
            }
            
            // 组合键处理
            if (event.ctrlKey) {
              switch (key) {
                case 'z':
                  if (event.shiftKey) {
                    redo() // Ctrl+Shift+Z 重做
                  } else {
                    undo() // Ctrl+Z 撤销
                  }
                  break
                case 'y':
                  redo() // Ctrl+Y 重做
                  break
                case 's':
                  saveImage() // Ctrl+S 保存
                  break
                case 'delete':
                  clearCanvas() // Ctrl+Delete 清空
                  break
              }
            }
            
            console.log('键盘快捷键:', key, event.ctrlKey ? '(Ctrl组合)' : '')
          }

          // ✅ 任务6完成: 撤销操作
          const undo = () => {
            if (canUndo.value) {
              historyIndex.value--
              const imageData = history.value[historyIndex.value]
              ctx.putImageData(imageData, 0, 0)
              
              showKeyboardHint.value = true
              keyboardHintText.value = `撤销成功 (${historyIndex.value + 1}/${history.value.length})`
              setTimeout(() => {
                showKeyboardHint.value = false
              }, 1000)
              
              console.log('撤销操作，当前索引:', historyIndex.value)
            } else {
              showKeyboardHint.value = true
              keyboardHintText.value = '无法撤销'
              setTimeout(() => {
                showKeyboardHint.value = false
              }, 1000)
            }
          }

          // ✅ 任务6完成: 重做操作
          const redo = () => {
            if (canRedo.value) {
              historyIndex.value++
              const imageData = history.value[historyIndex.value]
              ctx.putImageData(imageData, 0, 0)
              
              showKeyboardHint.value = true
              keyboardHintText.value = `重做成功 (${historyIndex.value + 1}/${history.value.length})`
              setTimeout(() => {
                showKeyboardHint.value = false
              }, 1000)
              
              console.log('重做操作，当前索引:', historyIndex.value)
            } else {
              showKeyboardHint.value = true
              keyboardHintText.value = '无法重做'
              setTimeout(() => {
                showKeyboardHint.value = false
              }, 1000)
            }
          }

          // 清空画布
          const clearCanvas = () => {
            ctx.clearRect(0, 0, canvasWidth.value, canvasHeight.value)
            
            // 重置统计信息
            strokeCount.value = 0
            
            // 保存清空后的状态
            saveState()
            
            showKeyboardHint.value = true
            keyboardHintText.value = '画布已清空'
            setTimeout(() => {
              showKeyboardHint.value = false
            }, 1000)
            
            console.log('画布已清空')
          }

          // 保存图片
          const saveImage = () => {
            // TODO: 实现保存图片逻辑
            showKeyboardHint.value = true
            keyboardHintText.value = '保存图片 (功能待实现)'
            setTimeout(() => {
              showKeyboardHint.value = false
            }, 1000)
            console.log('保存图片')
          }

          // ===== 生命周期 =====
          onMounted(() => {
            // 获取画布和上下文
            canvas.value = document.querySelector('canvas')
            ctx = canvas.value.getContext('2d')

            // ✅ 任务4完成: 初始化画布设置
            ctx.lineWidth = brushSize.value
            ctx.globalAlpha = opacity.value
            ctx.strokeStyle = currentColor.value
            ctx.lineCap = 'round'
            ctx.lineJoin = 'round'

            // ✅ 任务5完成: 添加全局键盘事件监听
            document.addEventListener('keydown', handleKeyboard)
            
            // 画布焦点事件
            canvas.value.addEventListener('focus', () => {
              hasFocus.value = true
              console.log('画布获得焦点')
            })
            
            canvas.value.addEventListener('blur', () => {
              hasFocus.value = false
              console.log('画布失去焦点')
            })
            
            // 确保画布可以获得焦点
            canvas.value.focus()

            // ✅ 任务6完成: 保存初始空白状态
            nextTick(() => {
              saveState()
            })

            console.log('画布初始化完成')
          })

          // ✅ 任务5完成: 清理事件监听器
          onUnmounted(() => {
            document.removeEventListener('keydown', handleKeyboard)
          })

          // ===== 返回给模板使用的数据和方法 =====
          return {
            // 数据
            canvas,
            isDrawing,
            currentTool,
            currentColor,
            brushSize,
            opacity,
            mouseX,
            mouseY,
            strokeCount,
            canvasWidth,
            canvasHeight,
            history,
            historyIndex,
            tools,
            colors,
            // 任务5新增
            lastKeyPressed,
            hasFocus,
            showKeyboardHint,
            keyboardHintText,

            // 计算属性
            canUndo,
            canRedo,

            // 方法
            getCurrentToolLabel,
            setTool,
            setColor,
            saveState,
            startDrawing,
            draw,
            stopDrawing,
            updateMousePosition,
            undo,
            redo,
            clearCanvas,
            saveImage,
            handleKeyboard
          }
        }
      }).mount('#app')
    </script>

    <!-- 学习提示 -->
    <script>
      console.log(`
✅ 任务6完成 - 撤销重做功能

🎯 已实现功能：

【任务1-5 - 基础功能】
✅ 工具选择、颜色选择、画笔设置、鼠标事件处理、键盘快捷键

【任务6 - 撤销重做功能】
1. ✅ 历史记录数据结构 (history数组, historyIndex索引)
2. ✅ 计算属性状态判断 (canUndo, canRedo)
3. ✅ :disabled 动态按钮状态控制
4. ✅ ctx.getImageData() 画布状态保存
5. ✅ ctx.putImageData() 画布状态恢复
6. ✅ saveState() 状态保存方法
7. ✅ undo() 撤销操作实现
8. ✅ redo() 重做操作实现
9. ✅ 历史记录数量限制 (maxHistorySize)
10. ✅ 绘制结束自动保存状态
11. ✅ 初始化时保存空白状态
12. ✅ 历史记录可视化指示器
13. ✅ 清空画布功能完善
14. ✅ 状态栏历史信息显示

🔧 关键技术点：
- Canvas状态保存恢复 (getImageData/putImageData)
- 计算属性实现状态判断 (computed)
- 按钮状态动态控制 (:disabled)
- 历史记录数组管理
- 索引指针控制
- 内存优化 (历史记录数量限制)
- 生命周期钩子应用 (nextTick)

📋 下一步：任务7 - Canvas绘制逻辑完善
        `)
    </script>
  </body>
</html>